home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Reference Guide
/
C-C++ Interactive Reference Guide.iso
/
c_ref
/
csource5
/
363_01
/
movem.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-16
|
12KB
|
362 lines
/***********************************************************************
*
* MOVEM - Instructions for 68020 Assembler
* Routines for the MOVEM instruction and the REG directive
*
* Function: movem()
* Builds MOVEM instructions. The size of the instruction is given by the
* size argument (assumed to be word if not specified). The label argument points to the label
* appearing on the source line containing the MOVEM instruction, if any,
* and the op argument points to the operands of the MOVEM instruction.
* The routine returns an error code in *errorPtr by the standard
* mechanism.
* Argument tablePtr is not used.
*
* reg()
* Defines a special register list symbol to be used as an argument for
* the MOVEM instruction. The size argument reflects the size code
* appended to the REG directive, which should be empty. The label
* argument points to the label appearing on the source line containing
* the REG directive (which must be specified), and the op argument
* points to a register list which is the new value of the symbol. The
* routine returns an error code in *errorPtr by the standard mechanism.
* Argument tablePtr is not used.
*
* Usage: movem(instruction *tablePtr, int size, char *label, char *op,
* int *errorPtr)
*
* reg(instruction *tablePtr, int size, char *label, char *op,
* int *errorPtr)
*
* Author: Paul McKee
* ECE492 North Carolina State University, 12/9/86
*
* Modified A.E. Romer. Version 1.0
* 17 March 1991: ANSI functions, braces layout.
*
************************************************************************/
#include <stdio.h>
#include <ctype.h>
#include "asm.h"
/* Define bit masks for the legal addressing modes of MOVEM */
#define ControlAlt (AnInd | AnIndDisp | AnIndIndex | AbsShort | AbsLong)
#define DestModes (ControlAlt | AnIndPre)
#define SourceModes (ControlAlt | AnIndPost | PCDisp | PCIndex)
extern long loc;
extern char pass2;
/* Define a couple of useful tests */
#define isTerm(c) (c == ',' || c == '/' || c == '-' || isspace(c) || !c)
#define isRegNum(c) ((c >= '0') && (c <= '7'))
char *evalList(char *p, unsigned short *listPtr, int *errorPtr)
{
char reg1, reg2, r;
unsigned short regList;
char symName[SIGCHARS+1];
char i;
symbolDef *symbol;
int status;
regList = 0;
/* Check whether the register list is specified
explicitly or as a register list symbol */
if ((p[0] == 'A' || p[0] == 'D') && isRegNum(p[1]) && isTerm(p[2]))
{
/* Assume it's explicit */
while (TRUE) /* Loop will be exited via return */
{
if ((p[0] == 'A' || p[0] == 'D') && isRegNum(p[1]))
{
if (p[0] == 'A')
reg1 = (char)(8) + p[1] - '0';
else
reg1 = p[1] - '0';
if (p[2] == '/')
{
/* Set the bit the for a single register */
regList |= (1 << reg1);
p += 3;
}
else if (p[2] == '-')
if ((p[3] == 'A' || p[3] == 'D') && isRegNum(p[4]) &&
isTerm(p[5]))
{
if (p[5] == '-')
{
NEWERROR(*errorPtr, SYNTAX);
return NULL;
}
if (p[3] == 'A')
reg2 = (char)(8) + p[4] - '0';
else
reg2 = p[4] - '0';
/* Set all the bits corresponding to registers
in the specified range */
if (reg1 < reg2)
for (r = reg1; r <= reg2; r++)
regList |= (1 << r);
else
for (r = reg2; r <= reg1; r++)
regList |= (1 << r);
if (p[5] != '/')
{
/* End of register list found - return its value */
*listPtr = regList;
return p+5;
}
p += 6;
}
else {
/* Invalid character found - return the error */
NEWERROR(*errorPtr, SYNTAX);
return NULL;
}
else
{
/* Set the bit the for a single register */
regList |= (1 << reg1);
/* End of register list found - return its value */
*listPtr = regList;
return p+2;
}
}
else
{
/* Invalid character found - return the error */
NEWERROR(*errorPtr, SYNTAX);
return NULL;
}
}
}
else
{
/* Try looking in the symbol table for a register list symbol */
if (!isalpha(*p) && *p != '.')
{
NEWERROR(*errorPtr, SYNTAX);
return NULL;
}
i = 0;
/* Collect characters of the symbol's name
(only SIGCHARS characters are significant) */
do
{
if (i < SIGCHARS)
symName[i++] = *p;
p++;
} while (isalnum(*p) || *p == '.' || *p == '_' || *p == '$');
/* Check for invalid syntax */
if (!isspace(*p) && *p != ',' && *p)
{
NEWERROR(*errorPtr, SYNTAX);
return NULL;
}
symName[i] = '\0';
/* Look up the name in the symbol table, resulting
in a pointer to the symbol table entry */
status = OK;
symbol = lookup(symName, &status);
if (status < SEVERE)
/* The register list symbol must be
previously defined in the program */
if (status == UNDEFINED)
{
NEWERROR(*errorPtr, status);
}
else if (pass2 && !(symbol->flags & BACKREF))
{
NEWERROR(*errorPtr, REG_LIST_UNDEF);
}
else
{
if (symbol->flags & REG_LIST_SYM)
*listPtr = (unsigned short)symbol->value;
else
{
NEWERROR(*errorPtr, NOT_REG_LIST);
*listPtr = 0x1234;
}
}
else
{
NEWERROR(*errorPtr, status);
*listPtr = 0;
}
return p;
}
return NORMAL;
}
int movem(instruction *tablePtr, int size, char *label, char *op,
int *errorPtr)
{
char *p;
int status;
unsigned short regList, temp, instMask;
char i;
opDescriptor memOp;
/* Pick mask according to size code (only .W and .L are valid) */
if (size == WORD)
instMask = 0x4880;
else if (size == LONG)
instMask = 0x48C0;
else
{
if (size)
NEWERROR(*errorPtr, INV_SIZE_CODE);
instMask = 0x4880;
}
/* Define the label attached to this instruction */
if (*label)
create(label, loc, errorPtr);
/* See if the instruction is of the form MOVEM <reg_list>,<ea> */
status = OK;
/* Parse the register list */
p = evalList(op, ®List, &status);
if (status == OK && *p == ',')
{
/* Parse the memory address */
p = opParse(++p, &memOp, &status);
NEWERROR(*errorPtr, status);
if (status < ERROR)
{
/* Check legality of addressing mode */
if (memOp.mode & DestModes)
{
/* It's good, now generate the instruction */
if (pass2)
{
output((long int) (instMask | effAddr(&memOp)), WORD);
loc += 2;
/* If the addressing mode is address
register indirect with predecrement,
reverse the bits in the register
list mask */
if (memOp.mode == AnIndPre)
{
temp = regList;
regList = 0;
for (i = 0; i < 16; i++)
{
regList <<= 1;
regList |= (temp & 1);
temp >>= 1;
}
}
output((long) regList, WORD);
loc += 2;
}
else
loc += 4;
extWords(&memOp, size, errorPtr);
return NORMAL;
}
else
{
NEWERROR(*errorPtr, INV_ADDR_MODE);
return NORMAL;
}
}
}
/* See if the instruction is of the form MOVEM <ea>,<reg_list> */
status = OK;
/* Parse the effective address */
p = opParse(op, &memOp, &status);
NEWERROR(*errorPtr, status);
if (status < ERROR && *p == ',')
{
/* Check the legality of the addressing mode */
if (memOp.mode & SourceModes)
{
/* Parse the register list */
status = OK;
p = evalList(++p, ®List, &status);
if (status == OK)
{
/* Everything's OK, now build the instruction */
if (pass2)
{
output((long) (instMask | 0x0400 | effAddr(&memOp)), WORD);
loc += 2;
output((long) (regList), WORD);
loc += 2;
}
else
loc += 4;
extWords(&memOp, size, errorPtr);
return NORMAL;
}
}
else
{
NEWERROR(*errorPtr, INV_ADDR_MODE);
return NORMAL;
}
}
/* If the instruction isn't of either form, then return an error */
NEWERROR(*errorPtr, status);
return NORMAL;
}
int reg(instruction *tablePtr, int size, char *label, char *op, int *errorPtr)
{
int status;
symbolDef *symbol;
unsigned short regList;
if (size)
NEWERROR(*errorPtr, INV_SIZE_CODE);
if (!*op)
{
NEWERROR(*errorPtr, SYNTAX);
return NORMAL;
}
op = evalList(op, ®List, errorPtr);
if (*errorPtr < SEVERE)
if (!*label)
{
NEWERROR(*errorPtr, LABEL_REQUIRED);
}
else
{
status = OK;
symbol = create(label, (long) regList, &status);
NEWERROR(*errorPtr, status);
if (status < ERROR)
symbol->flags |= REG_LIST_SYM;
}
return NORMAL;
}